package com.ccsc.auth.aspect;

import com.ccsc.auth.controller.BaseController;
import com.ccsc.auth.entity.ShiroUser;
import com.ccsc.auth.global.Constants;
import com.ccsc.auth.service.AuthService;
import com.ccsc.auth.utils.BaseResponse;
import com.ccsc.auth.utils.BindingError;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author 郭兴文
 * @version V1.0
 * @Title: 表单验证
 * @ClassName: ValidAspect.java
 * @Description: 基于AOP实现的表单验证拦截
 * @Date 2016年5月13日 上午10:00:00
 */

@Component
@Aspect
public class MaskingAspect extends BaseController {
    @Autowired
    private AuthService authService;

    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object aroundValidation(ProceedingJoinPoint pjp) throws Throwable {
        Object result;

        //方法级权限验证
        ShiroUser sessionUser = getSessionUser();
        RequestMapping classRm = (RequestMapping) pjp.getSignature().getDeclaringType().getAnnotation(RequestMapping.class);
        RequestMapping methodRm = ((MethodSignature) pjp.getSignature()).getMethod().getAnnotation(RequestMapping.class);
        Boolean isValid = authService.checkAuthority(sessionUser!=null ? sessionUser.getUserId() : null, classRm.value()[0], methodRm.value()[0]);
        if(!isValid){
            return this.error(Constants.NO_AUTHORITY, getMessageSource("800"));
        }

        //表单验证
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        if (!BaseResponse.class.equals(method.getReturnType()) && !"sysLogout".equals(method.getName())) {
            return pjp.proceed();
        }
        Object[] args = pjp.getArgs();
        Annotation[][] annotations = method.getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            if (!hasValidAnnotation(annotations[i])) {
                continue;
            }
            if (!(i < annotations.length - 1 && args[i + 1] instanceof BindingResult)) {
                //验证对象后面没有跟bindingResult,事实上如果没有应该到不了这一步
                continue;
            }
            BindingResult errResult = (BindingResult) args[i + 1];
            if (errResult.hasErrors()) {
                return this.error(Constants.FORM_VALID_FAIL, processErrors(errResult));
            }
        }

        //日志输出
        try{
            result = pjp.proceed();
        }
        catch (Exception ex)
        {
            throw new RuntimeException(ex);
        }
        return result;
    }

    private boolean hasValidAnnotation(Annotation[] annotations) {
        if (annotations == null) {
            return false;
        }
        for (Annotation annotation : annotations) {
            if (annotation instanceof Valid) {
                return true;
            }
        }
        return false;
    }

    private List<BindingError> processErrors(BindingResult result){
        if(result != null && result.hasErrors()){
            List<BindingError> list = Lists.newLinkedList();
            List<FieldError>  fieldErrors = result.getFieldErrors();
            List<String> sortFieldList = Lists.newLinkedList();

            Object object = result.getTarget();
            if(object != null){
                Field[] fields = object.getClass().getDeclaredFields();
                for (int j = 0; j < fields.length; j++) {
                    if(!Strings.isNullOrEmpty(fields[j].getName())){
                        sortFieldList.add(fields[j].getName());
                    }
                }
                }

                if(sortFieldList != null && sortFieldList.size() > 0){
                    for(String fieldName : sortFieldList) {
                        for (int i = 0; i < fieldErrors.size(); i++) {
                            FieldError fieldError = fieldErrors.get(i);
                            String errorFieldName = fieldError.getField();
                            if(fieldName.equals(errorFieldName)){
                                BindingError be = new BindingError();
                                be.setId(fieldError.getField());
                                be.setMessage(fieldError.getDefaultMessage());
                                list.add(be);
                            }
                        }
                    }
                }

                if(list.size() == 0){
                    for (int i = 0; i < fieldErrors.size(); i++) {
                        FieldError fieldError = fieldErrors.get(i);
                        BindingError be = new BindingError();
                        be.setId(fieldError.getField());
                        be.setMessage(fieldError.getDefaultMessage());
                        list.add(be);
                        }
                }

            return list;
        }
        return null;
    }
}